//
//  ViewController.m
//  GCDSomeConfusingPlaces
//
//  Created by xufeng on 2016/12/27.
//  Copyright © 2016年 xufeng. All rights reserved.
//

/**
 *
 * GCD 容易让人迷惑的几个小问题
 * http://ios.jobbole.com/91825/
 *
 */

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    /**
     *
     * 迷惑一：队列和线程的关系
     * 迷惑二：GCD的死锁
     * 迷惑三：以下这些API的异同与作用场景：dispatch_async、dispatch_sync、dispatch_barrier_async、dispatch_barrier_syn
     *
     */

    // 迷惑一：队列和线程的关系
    /**
       对我们使用者来说，与其说GCD是面向线程的，不如说是面向队列的。 它隐藏了内部线程的调度。
       我们所做的仅仅是创建不同的队列，把Block追加到队列中去执行，而队列是FIFO（先进先出）的。
       它会按照我们追加的Block的顺序，在综合我们调用的gcd的api（sync、async、dispatch_barrier_async等等），以及根据系统负载来增减线程并发数， 来调度线程执行Block。
     */

    dispatch_queue_t queue = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        NSLog(@"log_1=%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"log_2=%@", [NSThread currentThread]);
    });
    //    dispatch_sync(dispatch_get_main_queue(), ^{
//        NSLog(@"%@", [NSThread currentThread]);
//    });
    dispatch_async(queue, ^{
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"log_3=%@", [NSThread currentThread]);
        });
    });
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"log_4=%@", [NSThread currentThread]);
    });
    /**
        往主队列提交Block，无论是sync，还是async，都是在主线程中执行。
        往非主队列中提交，如果是sync，会在当前提交Block的线程中执行。如果是async，则会在分线程中执行。
     */
    /**
       上文需要注意以下两点:
       这里的sync，async并不局限于dispatch_sync、dispatch_async，而指的是GCD中所有同步异步的API。
       这里我们用的是并行queue，如果用串行queue，结果也是一样的。
       唯一的区别是并行queue会权衡当前系统负载，去同时并发几条线程去执行Block，而串行queue中，始终只会在同一条线程中执行Block。
     */
    // 迷惑二：GCD的死锁
//    dispatch_sync(dispatch_get_main_queue(), ^{
//        NSLog(@"task one");
//    });
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"任务一");
    });
    NSLog(@"任务二");
    NSLog(@"log_5=ask two");
    /**
      如上，在主线程中，往主队列同步提交了任务一。因为往queue中提交Block，总是追加在队列尾部的，
      而queue执行Block的顺序为先进先出（FIFO），所以任务一需要在当前队列它之前的任务（任务二）全部执行完，才能轮到它。
      而任务二因为任务一的sync，被阻塞了，它需要等任务一执行完才能被执行。两者互相等待对方执行完，才能执行，程序被死锁在这了。
      这里需要注意这里死锁的很重要一个条件也因为主队列是一个串行的队列(主队列中只有一条主线程)。如果我们如下例，在并行队列中提交，
      则不会造成死锁：
     */
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_sync(dispatch_get_global_queue(0, 0), ^{
            NSLog(@"log_6=task three");
        });
        NSLog(@"log_7=task four");
    });

    /**
     * 如果同步（sync）提交一个Block到一个串行队列，而提交Block这个动作所处的线程，也是在当前队列，就会引起死锁。
     */

}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.         ®
}


@end
